273 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
$(document).ready(function () {
 | 
						|
  var bootcamps = ''
 | 
						|
  $.getJSON('/json/bootcamps.json', function(data) {
 | 
						|
    bootcamps = data;
 | 
						|
  });
 | 
						|
  var city = "";
 | 
						|
  $("body").data("state", "stacked");
 | 
						|
  $('#city-buttons').on("click", "button", function () {
 | 
						|
    $(this).addClass('animated pulse');
 | 
						|
    city = $(this).attr("id");
 | 
						|
    $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
 | 
						|
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
 | 
						|
      }) + ', and making $_______, your true costs will be:');
 | 
						|
    setTimeout(function () {
 | 
						|
      $('#city-buttons').hide();
 | 
						|
      $('#income').addClass('animated fadeIn').show();
 | 
						|
    }, 1000);
 | 
						|
  });
 | 
						|
  $('#income').on("click", "button", function () {
 | 
						|
    $(this).addClass('animated pulse');
 | 
						|
    setTimeout(function () {
 | 
						|
      $('#income').hide();
 | 
						|
      $('#chart').addClass('animated fadeIn').show();
 | 
						|
      $('#chart-controls').addClass('animated fadeIn').show();
 | 
						|
      $('#explanation').addClass('animated fadeIn').show();
 | 
						|
    }, 1000);
 | 
						|
    var lastYearsIncome = parseInt($(this).attr("id"));
 | 
						|
    $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
 | 
						|
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
 | 
						|
      }) + ', and making $' + lastYearsIncome.toString().replace(/0000$/, '0,000') + ', your true costs will be:');
 | 
						|
    var categoryNames = ['Lost Wages', 'Financing Cost', 'Housing Cost', 'Tuition / Est. Wage Garnishing'];
 | 
						|
    bootcamps.forEach(function (camp) {
 | 
						|
      var x0 = 0;
 | 
						|
      if (camp.cities.indexOf(city) > -1) {
 | 
						|
        weeklyHousing = 0;
 | 
						|
      } else {
 | 
						|
        weeklyHousing = +camp.housing;
 | 
						|
      }
 | 
						|
      camp.mapping = [{
 | 
						|
        name: camp.name,
 | 
						|
        label: 'Tuition / Est. Wage Garnishing',
 | 
						|
        value: +camp.cost,
 | 
						|
        x0: x0,
 | 
						|
        x1: x0 += +camp.cost
 | 
						|
      }, {
 | 
						|
        name: camp.name,
 | 
						|
        label: 'Financing Cost',
 | 
						|
        value: +Math.floor(camp.cost * .09519),
 | 
						|
        x0: +camp.cost,
 | 
						|
        x1: camp.finance ? x0 += +Math.floor(camp.cost * .09519) : 0
 | 
						|
      }, {
 | 
						|
        name: camp.name,
 | 
						|
        label: 'Housing Cost',
 | 
						|
        value: +weeklyHousing * camp.weeks,
 | 
						|
        x0: camp.finance ? +Math.floor(camp.cost * 1.09519) : camp.cost,
 | 
						|
        x1: x0 += weeklyHousing * camp.weeks
 | 
						|
      }, {
 | 
						|
        name: camp.name,
 | 
						|
        label: 'Lost Wages',
 | 
						|
        value: +(Math.floor(camp.weeks * lastYearsIncome / 50)),
 | 
						|
        x0: camp.finance ? +(Math.floor(camp.cost * 1.09519) + weeklyHousing * camp.weeks) : +camp.cost + weeklyHousing * camp.weeks,
 | 
						|
        x1: x0 += +(Math.floor(camp.weeks * lastYearsIncome / 50))
 | 
						|
      }];
 | 
						|
      camp.total = camp.mapping[camp.mapping.length - 1].x1;
 | 
						|
    });
 | 
						|
    bootcamps.sort(function (a, b) {
 | 
						|
      return a.total - b.total;
 | 
						|
    });
 | 
						|
    maxValue = 0;
 | 
						|
    bootcamps.forEach(function (camp) {
 | 
						|
      camp.mapping.forEach(function (elem) {
 | 
						|
        if (elem.value > maxValue) {
 | 
						|
          maxValue = elem.value;
 | 
						|
        }
 | 
						|
      });
 | 
						|
    });
 | 
						|
    var xStackMax = d3.max(bootcamps, function (d) {
 | 
						|
        return d.total;
 | 
						|
      }), //Scale for Stacked
 | 
						|
      xGroupMax = bootcamps.map(function (camp) {
 | 
						|
        return camp.mapping.reduce(function (a, b) {
 | 
						|
          return a.value > b.value ? a.value : b.value;
 | 
						|
        });
 | 
						|
      }).reduce(function (a, b) {
 | 
						|
        return a > b ? a : b;
 | 
						|
      });
 | 
						|
    var margin = {
 | 
						|
        top: 30,
 | 
						|
        right: 60,
 | 
						|
        bottom: 50,
 | 
						|
        left: 140
 | 
						|
      },
 | 
						|
      width = 800 - margin.left - margin.right,
 | 
						|
      height = 1200 - margin.top - margin.bottom;
 | 
						|
    var barHeight = 20;
 | 
						|
    var xScale = d3.scale.linear()
 | 
						|
      .domain([0, xStackMax])
 | 
						|
      .rangeRound([0, width]);
 | 
						|
    var y0Scale = d3.scale.ordinal()
 | 
						|
      .domain(bootcamps.map(function (d) {
 | 
						|
        return d.name;
 | 
						|
      }))
 | 
						|
      .rangeRoundBands([0, height], .1);
 | 
						|
    var y1Scale = d3.scale.ordinal()
 | 
						|
      .domain(categoryNames).rangeRoundBands([0, y0Scale.rangeBand()]);
 | 
						|
    var color = d3.scale.ordinal()
 | 
						|
      .range(["#215f1e", "#5f5c1e", "#1e215f", "#5c1e5f"])
 | 
						|
      .domain(categoryNames);
 | 
						|
    var svg = d3.select("svg")
 | 
						|
      .attr("width", width + margin.left + margin.right)
 | 
						|
      .attr("height", height + margin.top + margin.bottom)
 | 
						|
      .append("g")
 | 
						|
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
 | 
						|
    var selection = svg.selectAll(".series")
 | 
						|
      .data(bootcamps)
 | 
						|
      .enter().append("g")
 | 
						|
      .attr("class", "series")
 | 
						|
      .attr("transform", function (d) {
 | 
						|
        return "translate(0," + y0Scale(d.name) + ")";
 | 
						|
      });
 | 
						|
    var rect = selection.selectAll("rect")
 | 
						|
      .data(function (d) {
 | 
						|
        return d.mapping;
 | 
						|
      })
 | 
						|
      .enter().append("rect")
 | 
						|
      .attr("x", 0)
 | 
						|
      .attr("width", 0)
 | 
						|
      .attr("height", y0Scale.rangeBand())
 | 
						|
      .style("fill", function (d) {
 | 
						|
        return color(d.label);
 | 
						|
      })
 | 
						|
      .style("stroke", "white")
 | 
						|
      .on("mouseover", function (d) {
 | 
						|
        showPopover.call(this, d);
 | 
						|
      })
 | 
						|
      .on("mouseout", function (d) {
 | 
						|
        removePopovers();
 | 
						|
      });
 | 
						|
    rect.transition()
 | 
						|
      .delay(function (d, i) {
 | 
						|
        return i * 10;
 | 
						|
      })
 | 
						|
      .attr("x", function (d) {
 | 
						|
        return xScale(d.x0);
 | 
						|
      })
 | 
						|
      .attr("width", function (d) {
 | 
						|
        return xScale((d.x1) - (d.x0));
 | 
						|
      });
 | 
						|
    d3.selectAll("#transform").on("click", function () {
 | 
						|
      $('#transform').addClass('animated pulse');
 | 
						|
      change();
 | 
						|
      setTimeout(function () {
 | 
						|
        $('#transform').removeClass('animated pulse');
 | 
						|
      }, 1000);
 | 
						|
    });
 | 
						|
 | 
						|
    d3.selectAll("#chart").on("click", function () {
 | 
						|
      change();
 | 
						|
    });
 | 
						|
 | 
						|
    function change() {
 | 
						|
      if ($("body").data("state") === "stacked") {
 | 
						|
        transitionGrouped();
 | 
						|
        $("body").data("state", "grouped");
 | 
						|
      } else {
 | 
						|
        transitionStacked();
 | 
						|
        $("body").data("state", "stacked");
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    function transitionGrouped() {
 | 
						|
      xScale.domain = ([0, xGroupMax]);
 | 
						|
      rect.transition()
 | 
						|
        .duration(500)
 | 
						|
        .delay(function (d, i) {
 | 
						|
          return i * 10;
 | 
						|
        })
 | 
						|
        .attr("width", function (d) {
 | 
						|
          return xScale((d.x1) - (d.x0));
 | 
						|
        })
 | 
						|
        .transition()
 | 
						|
        .attr("y", function (d) {
 | 
						|
          return y1Scale(d.label);
 | 
						|
        })
 | 
						|
        .attr("x", 0)
 | 
						|
        .attr("height", y1Scale.rangeBand());
 | 
						|
    }
 | 
						|
 | 
						|
    function transitionStacked() {
 | 
						|
      xScale.domain = ([0, xStackMax]);
 | 
						|
      rect.transition()
 | 
						|
        .duration(500)
 | 
						|
        .delay(function (d, i) {
 | 
						|
          return i * 10;
 | 
						|
        })
 | 
						|
        .attr("x", function (d) {
 | 
						|
          return xScale(d.x0);
 | 
						|
        })
 | 
						|
        .transition()
 | 
						|
        .attr("y", function (d) {
 | 
						|
          return y0Scale(d.label);
 | 
						|
        })
 | 
						|
        .attr("height", y0Scale.rangeBand());
 | 
						|
    }
 | 
						|
 | 
						|
    //axes
 | 
						|
    var xAxis = d3.svg.axis()
 | 
						|
      .scale(xScale)
 | 
						|
      .orient("bottom");
 | 
						|
    var yAxis = d3.svg.axis()
 | 
						|
      .scale(y0Scale)
 | 
						|
      .orient("left");
 | 
						|
    svg.append("g")
 | 
						|
      .attr("class", "y axis")
 | 
						|
      .call(yAxis);
 | 
						|
    svg.append("g")
 | 
						|
      .attr("class", "x axis")
 | 
						|
      .attr("transform", "translate(0," + height + ")")
 | 
						|
      .call(xAxis)
 | 
						|
      .append("text")
 | 
						|
      .attr("x", 300)
 | 
						|
      .attr("y", 35)
 | 
						|
      .attr("dy", ".35em")
 | 
						|
      .style("text-anchor", "middle")
 | 
						|
      .text("Cost in $USD");
 | 
						|
    //tooltips
 | 
						|
    function removePopovers() {
 | 
						|
      $('.popover').each(function () {
 | 
						|
        $(this).remove();
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    function showPopover(d) {
 | 
						|
      $(this).popover({
 | 
						|
        title: d.name,
 | 
						|
        placement: 'auto top',
 | 
						|
        container: 'body',
 | 
						|
        trigger: 'manual',
 | 
						|
        html: true,
 | 
						|
        content: function () {
 | 
						|
          return d.label +
 | 
						|
            "<br/>$" +
 | 
						|
            d3.format(",")(d.value ? d.value : d.x1 - d.x0);
 | 
						|
        }
 | 
						|
      });
 | 
						|
      $(this).popover('show');
 | 
						|
    }
 | 
						|
 | 
						|
    //legends
 | 
						|
    var legend = svg.selectAll(".legend")
 | 
						|
      .data(categoryNames.slice().reverse())
 | 
						|
      .enter().append("g")
 | 
						|
      .attr("class", "legend")
 | 
						|
      .attr("transform", function (d, i) {
 | 
						|
        return "translate(30," + i * y0Scale.rangeBand() * 1.1 + ")";
 | 
						|
      });
 | 
						|
    legend.append("rect")
 | 
						|
      .attr("x", width - y0Scale.rangeBand())
 | 
						|
      .attr("width", y0Scale.rangeBand())
 | 
						|
      .attr("height", y0Scale.rangeBand())
 | 
						|
      .style("fill", color)
 | 
						|
      .style("stroke", "white");
 | 
						|
    legend.append("text")
 | 
						|
      .attr("x", width - y0Scale.rangeBand() * 1.2)
 | 
						|
      .attr("y", 12)
 | 
						|
      .attr("dy", ".35em")
 | 
						|
      .style("text-anchor", "end")
 | 
						|
      .text(function (d) {
 | 
						|
        return d;
 | 
						|
      });
 | 
						|
  });
 | 
						|
});
 |